namespace RAYTRACING {
    //往quad数据填入三角索引
    function fillIndexQuad(indexs: number[], startIdx: number) {
        // startIdx /= 3;
        indexs.push(startIdx + 0, startIdx + 1, startIdx + 2, startIdx + 2, startIdx + 1, startIdx + 3);
    }

    export enum DefMeshType {
        Cube,
        Quad,
        Cylinder,
        Sphere
    }

    /** 默认资源 */
    export class DefRes {

        public static GetMesh(meshType: DefMeshType): Mesh {
            let _mesh: Mesh = new Mesh();
            let _data: MeshData;
            switch (meshType) {
                case DefMeshType.Cube: _data = this.GenCube(); break;
                case DefMeshType.Quad: _data = this.GenQuadData(); break;
                case DefMeshType.Sphere: _data = this.GenSphere(); break;
            }
            _mesh.data = _data;
            return _mesh;
        }

        private static GenCube(size: number = 1): MeshData {
            let half = size * 0.5;
            let data = new MeshData();
            let poss: Vector3[] = [];
            let uvs: Vector2[] = [];
            let triindexs: number[] = [];
            //bottom
            fillIndexQuad(triindexs, poss.length);
            poss.push(new Vector3(-half, -half, -half), new Vector3(-half, -half, half), new Vector3(half, -half, -half), new Vector3(half, -half, half));
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0));
            //top
            fillIndexQuad(triindexs, poss.length);
            poss.push(new Vector3(-half, half, half), new Vector3(-half, half, -half), new Vector3(half, half, half), new Vector3(half, half, -half));
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0));
            //back
            fillIndexQuad(triindexs, poss.length);
            poss.push(new Vector3(-half, -half, half), new Vector3(-half, half, half), new Vector3(half, -half, half), new Vector3(half, half, half));
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0));
            //front
            fillIndexQuad(triindexs, poss.length);
            poss.push(new Vector3(-half, half, -half), new Vector3(-half, -half, -half), new Vector3(half, half, -half), new Vector3(half, -half, -half));
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0));
            //right
            fillIndexQuad(triindexs, poss.length);
            poss.push(new Vector3(half, -half, -half), new Vector3(half, -half, half), new Vector3(half, half, -half), new Vector3(half, half, half));
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0));
            //left
            fillIndexQuad(triindexs, poss.length);
            poss.push(new Vector3(-half, -half, half), new Vector3(-half, -half, -half), new Vector3(-half, half, half), new Vector3(-half, half, -half));
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(0, 0), new Vector2(1, 0));

            //
            data.indexBuf = triindexs;
            // data.normalBuf = normals;
            data.posBuf = poss;
            data.uvBuf = uvs;
            return data;
        }

        private static GenQuadData(size: number = 1): MeshData {
            let half = size / 2;
            let data = new MeshData();
            let poss: Vector3[] = [];
            let uvs: Vector2[] = [];
            let triindexs: number[] = [];
            let normals: Vector3[] = [];
            //set data
            //   0 -------- 1
            //     |      |
            //     |      |
            //   3 -------- 2
            //
            poss.push(new Vector3(-half, half, 0), new Vector3(half, half, 0), new Vector3(half, -half, 0), new Vector3(-half, -half, 0));
            // poss.push(-half, half, 0, half, half, 0, half, -half, 0, -half, -half, 0);
            normals.push(new Vector3(0, 0, -1), new Vector3(0, 0, -1));
            // normals.push(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1);
            uvs.push(new Vector2(0, 1), new Vector2(1, 1), new Vector2(1, 0), new Vector2(0, 0));
            // uvs.push(0, 1, 1, 1, 1, 0, 0, 0);
            triindexs.push(0, 1, 3, 1, 2, 3);
            //
            data.indexBuf = triindexs;
            data.normalBuf = normals;
            data.posBuf = poss;
            data.uvBuf = uvs;
            return data;
        }

        /**
         * 生成一个球形mesh
         * @param size 尺寸（半径）
         * @param xSegments X 轴向点分段数
         * @param YSegments Y 轴向点分段数
         * @returns 
         */
        private static GenSphere(size: number = 0.5, xSegments: number = 24, YSegments: number = 12) {
            let data = new MeshData();
            let poss: Vector3[] = [];
            let uvs: Vector2[] = [];
            let triindexs: number[] = [];
            let normals: Vector3[] = [];

            xSegments = Math.max(3, Math.floor(xSegments));
            YSegments = Math.max(2, Math.floor(YSegments));

            let ix, iy;

            let index = 0;
            let grid = [];

            // generate vertices, normals and uvs
            for (iy = 0; iy <= YSegments; iy++) {
                let verticesRow = [];
                let v = iy / YSegments;
                for (ix = 0; ix <= xSegments; ix++) {
                    let u = ix / xSegments;
                    let vertex = new Vector3();

                    // vertex
                    vertex.x = - size * Math.cos(u * Math.PI * 2) * Math.sin(v * Math.PI);
                    vertex.y = size * Math.cos(v * Math.PI);
                    vertex.z = size * Math.sin(u * Math.PI * 2) * Math.sin(v * Math.PI);

                    poss.push(vertex);

                    let val = poss.length % 3;
                    if (val == 0) {
                        // normal
                        let normal = new Vector3(vertex.x, vertex.y, vertex.z);
                        let num: number = Math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
                        if (num > Number.MIN_VALUE) {
                            normal.x = normal.x / num;
                            normal.y = normal.y / num;
                            normal.z = normal.z / num;
                        }
                        else {
                            normal.x = 0;
                            normal.y = 0;
                            normal.z = 0;
                        }
                        normals.push(normal);
                    }

                    // uv
                    let uv = new Vector2(1 - u, v);
                    uvs.push(uv);
                    verticesRow.push(index++);
                }
                grid.push(verticesRow);
            }

            // indices
            for (iy = 0; iy < YSegments; iy++) {
                for (ix = 0; ix < xSegments; ix++) {
                    let a = grid[iy][ix + 1];
                    let b = grid[iy][ix];
                    let c = grid[iy + 1][ix];
                    let d = grid[iy + 1][ix + 1];

                    if (iy !== 0) triindexs.push(a, d, b);
                    if (iy !== YSegments - 1) triindexs.push(b, d, c);
                }
            }

            //
            data.indexBuf = triindexs;
            data.normalBuf = normals;
            data.posBuf = poss;
            data.uvBuf = uvs;

            return data;
        }
    }
}